﻿//
// ParallelGrep
//
// Copyright (C) 2011 - Tatsuya Niioka
//
using System;
using System.Threading;
using System.ComponentModel;
using GrepEngine;
using System.Threading.Tasks;
using ParallelGrep.Properties;
namespace ParallelGrep.Worker
{
    /// <summary>
    /// GrepWorkerクラス
    /// </summary>
    public class GrepWorker
    {
        private GrepInfo m_info = null;

        #region Constructor
        /// <summary>
        /// 指定したGrep情報で、新しいクラスを生成します。
        /// </summary>
        /// <param name="info">Grep情報</param>
        public GrepWorker(GrepInfo info)
        {
            m_info = info;
        }
        #endregion

        #region FileCount
        private int m_fileCount = 0;
        /// <summary>
        /// ファイル数を取得または設定します。
        /// </summary>
        public int FileCount
        {
            get { return m_fileCount; }
            set { m_fileCount = value; }
        }
        #endregion

        #region Completed
        private bool m_completed = false;
        /// <summary>
        /// バックグラウンド操作が完了したかどうかを示す値を取得します。
        /// </summary>
        public bool Completed
        {
            get { return m_completed; }
            set { m_completed = value; }
        }
        #endregion

        #region CancellationPending
        private bool m_cancellationPending = false;
        /// <summary>
        /// バックグラウンド操作のキャンセルを要求したかどうかを示す値を取得します。 
        /// </summary>
        internal bool CancellationPending
        {
            get { return m_cancellationPending; }
            set { m_cancellationPending = value; }
        }
        #endregion

        #region RunWorkerAsync
        /// <summary>
        /// バックグラウンド操作の実行を開始します。
        /// </summary>
        public void RunWorkerAsync()
        {
            BackgroundWorker worker = new BackgroundWorker();
            worker.DoWork += new DoWorkEventHandler(worker_DoWork);
            worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
            worker.RunWorkerAsync();
        }
        #endregion

        #region worker_DoWork
        /// <summary>
        /// ワーカー実行イベント処理を実行します。
        /// </summary>
        /// <param name="sender">送信オブジェクト</param>
        /// <param name="e">イベントデータ</param>
        private void worker_DoWork(object sender, DoWorkEventArgs e)
        {
            Completed = false;
            CancellationPending = false;
            FileCount = 0;
            BackgroundWorker worker = sender as BackgroundWorker;
            CancellationPending = false;
            Grep grep = new Grep(m_info);
            grep.OnGreped += new EventHandler<GrepedEventArgs>(grep_OnGreped);
            grep.OnReplaced += new EventHandler<ReplacedEventArgs>(grep_OnReplaced);
            grep.OnDeleted += new EventHandler<DeletedEventArgs>(grep_OnDeleted);
            grep.OnIndentConverted += new EventHandler<IndentConvertedEventArgs>(grep_OnIndentConverted);
            grep.OnCharCodeConverted += new EventHandler<CharCodeConvertedEventArgs>(grep_OnCharCodeConverted);
            grep.OnLineTrim += new EventHandler<LineTrimConvertedEventArgs>(grep_OnLineTrimConverted);
            grep.OnProgress += new EventHandler<ProgressEventArgs>(grep_OnProgress);
            grep.OnCompleted += new EventHandler<CompletedEventArgs>(grep_OnCompleted);
            Task.Factory.StartNew(() =>
            {
                while (true)
                {
                    Thread.Sleep(1000); // 1 Second
                    if (CancellationPending)
                    {
                        grep.Cancel();
                        return;
                    }
                    if (Completed)
                    {
                        return;
                    }
                }
            });

            grep.Run(); // Pallalel
            FileCount = grep.FileCount;
        }
        #endregion

        #region worker_RunWorkerCompleted
        /// <summary>
        /// ワーカー完了通知イベント処理を実行します。
        /// </summary>
        /// <param name="sender">送信オブジェクト</param>
        /// <param name="e">イベントデータ</param>
        private void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            Completed = true;
            RaiseCompleted(new GrepWorkerCompletedEventArgs(FileCount, CancellationPending));
        }
        #endregion

        #region CancelAsync
        /// <summary>
        /// 保留中のバックグラウンド操作のキャンセルを要求します。 
        /// </summary>
        public void CancelAsync()
        {
            CancellationPending = true;
        }
        #endregion

        #region grep_OnProgress
        /// <summary>
        /// 進行状況通知イベント処理を実行します。
        /// </summary>
        /// <param name="sender">送信オブジェクト</param>
        /// <param name="e">イベントデータ</param>
        private void grep_OnProgress(object sender, ProgressEventArgs e)
        {
            RaiseProgress(new GrepWorkerProgressEventArgs(e.FileName));
        }
        #endregion

        #region grep_OnGreped
        /// <summary>
        /// Grep通知イベント処理を実行します。
        /// </summary>
        /// <param name="sender">送信オブジェクト</param>
        /// <param name="e">イベントデータ</param>
        private void grep_OnGreped(object sender, GrepedEventArgs e)
        {
            lock (this)
            {
                foreach (GrepMatche match in e.Matches)
                {
                    RaiseGreped(new GrepWorkerGrepedEventArgs(e.FileName, match.LineNumber, match.ColumnIndex, e.Size, e.Encoding, match.Text));
                }
            }
        }
        #endregion

        #region grep_OnReplaced
        /// <summary>
        /// 置換通知イベント処理を実行します。
        /// </summary>
        /// <param name="sender">送信オブジェクト</param>
        /// <param name="e">イベントデータ</param>
        private void grep_OnReplaced(object sender, ReplacedEventArgs e)
        {
            string msg = string.Format(Resources.ReplacedMessage, e.ReplaceCount);
            RaiseGreped(new GrepWorkerGrepedEventArgs(e.FileName, 0, 0, e.Size, e.Encoding, msg));
        }
        #endregion

        #region grep_OnDeleted
        /// <summary>
        /// 削除通知イベント処理を実行します。
        /// </summary>
        /// <param name="sender">送信オブジェクト</param>
        /// <param name="e">イベントデータ</param>
        private void grep_OnDeleted(object sender, DeletedEventArgs e)
        {
            string msg = string.Format(Resources.DeletedMessage, e.DeleteCount);
            RaiseGreped(new GrepWorkerGrepedEventArgs(e.FileName, 0, 0, e.Size, e.Encoding, msg));
        }
        #endregion

        #region grep_OnCharCodeConverted
        /// <summary>
        /// 文字コード変換通知イベント処理を実行します。
        /// </summary>
        /// <param name="sender">送信オブジェクト</param>
        /// <param name="e">イベントデータ</param>
        private void grep_OnCharCodeConverted(object sender, CharCodeConvertedEventArgs e)
        {
            string msg = null;
            if (e.IsEncodingConvert && e.IsLineEndConvert)
            {
                msg = Resources.CharCodeMessage1;
            }
            else if (e.IsEncodingConvert && !e.IsLineEndConvert)
            {
                msg = Resources.CharCodeMessage2;
            }
            else if (!e.IsEncodingConvert && e.IsLineEndConvert)
            {
                msg = Resources.CharCodeMessage3;
            }
            else
            {
                msg = "";   //ここは無い。
            }
            RaiseGreped(new GrepWorkerGrepedEventArgs(e.FileName, 0, 0, e.Size, e.Encoding, msg));
        }
        #endregion

        #region grep_OnIndentConverted
        /// <summary>
        /// インデント変換通知イベント処理を実行します。
        /// </summary>
        /// <param name="sender">送信オブジェクト</param>
        /// <param name="e">イベントデータ</param>
        private void grep_OnIndentConverted(object sender, IndentConvertedEventArgs e)
        {
            string msg = string.Format(Resources.IndentMessage, e.LineCount);
            RaiseGreped(new GrepWorkerGrepedEventArgs(e.FileName, 0, 0, e.Size, e.Encoding, msg));
        }
        #endregion

        #region grep_OnLineTrimConverted
        /// <summary>
        /// 行Trim通知イベント処理を実行します。
        /// </summary>
        /// <param name="sender">送信オブジェクト</param>
        /// <param name="e">イベントデータ</param>
        private void grep_OnLineTrimConverted(object sender, LineTrimConvertedEventArgs e)
        {
            string msg = string.Format(Resources.LineTrimMessage, e.LineCount);
            RaiseGreped(new GrepWorkerGrepedEventArgs(e.FileName, 0, 0, e.Size, e.Encoding, msg));
        }
        #endregion

        #region grep_OnCompleted
        /// <summary>
        /// 完了通知イベント処理を実行します。
        /// </summary>
        /// <param name="sender">送信オブジェクト</param>
        /// <param name="e">イベントデータ</param>
        private void grep_OnCompleted(object sender, CompletedEventArgs e)
        {
            RaiseCompleted(new GrepWorkerCompletedEventArgs(e.FileCount, true));
        }
        #endregion

        #region OnProgress
        /// <summary>
        /// 進行状況イベント
        /// </summary>
        public event EventHandler<GrepWorkerProgressEventArgs> OnProgress;
        /// <summary>
        /// Progressイベントを実行します。
        /// </summary>
        /// <param name="e"></param>
        internal void RaiseProgress(GrepWorkerProgressEventArgs e)
        {
            if (OnProgress != null)
            {
                OnProgress(this, e);
            }
        }
        #endregion

        #region OnGreped
        /// <summary>
        /// 検索イベント
        /// </summary>
        public event EventHandler<GrepWorkerGrepedEventArgs> OnGreped;
        /// <summary>
        /// 検索イベントを実行します。
        /// </summary>
        /// <param name="e">イベントデータ</param>
        internal void RaiseGreped(GrepWorkerGrepedEventArgs e)
        {
            if (OnGreped != null)
            {
                OnGreped(this, e);
            }
        }
        #endregion

        #region OnCompleted
        /// <summary>
        /// 完了イベント
        /// </summary>
        public event EventHandler<GrepWorkerCompletedEventArgs> OnCompleted;
        /// <summary>
        /// Completedイベントを実行します。
        /// </summary>
        /// <param name="e">イベントデータ</param>
        internal void RaiseCompleted(GrepWorkerCompletedEventArgs e)
        {
            if (OnCompleted != null)
            {
                OnCompleted(this, e);
            }
        }
        #endregion
    }
}
